package util

import (
	"gitee.com/kuntu-projects/go-kuntu-jkit/base/util/function"
	"math"
	"reflect"
	"strconv"
)

// ==================
// util-array_list: array list
// ==================

// defaultCapacity 默认空间大小
const defaultCapacity = 10

type ArrayList[E any] struct {
	AbstractList[E]
	elementData      []E
	size             int
	modCount         int
	emptyElementData []E
}

func NewArrayList[E any]() *ArrayList[E] {
	return NewArrayListBySize[E](defaultCapacity)
}

func NewArrayListBySize[E any](initialCapacity int) *ArrayList[E] {
	absList := NewAbstractList[E]()
	list := new(ArrayList[E])
	list.emptyElementData = make([]E, 0)

	if initialCapacity > 0 {
		list.elementData = make([]E, initialCapacity)
	} else if initialCapacity == 0 {
		list.elementData = list.emptyElementData
	} else {
		panic("invalid initial capacity" + strconv.Itoa(initialCapacity))
	}
	list.size = 0
	list.modCount = 0
	list.AbstractList = absList
	return list
}

func (receiver *ArrayList[E]) Add(e E) bool {
	receiver.add(e, receiver.elementData, receiver.size)
	return true
}

func (receiver *ArrayList[E]) Get(index int) E {
	if index >= receiver.Size() {
		panic("index out of range")
	} else {
		return receiver.elementData[index]
	}
}

// Set 把obj放在index位置
func (receiver *ArrayList[E]) Set(index int, obj E) E {
	if index >= receiver.Size() {
		panic("index out of range")
	} else {
		old := receiver.elementData[index]
		receiver.elementData[index] = obj
		return old
	}
}

// AddByIndex 添加到指定index位置
func (receiver *ArrayList[E]) AddByIndex(index int, obj E) {
	rangeCheckForAdd(index, receiver.size)
	if index >= receiver.Size() {
		receiver.grow()
	}
	receiver.size = receiver.size + 1
	receiver.elementData[index] = obj
}

// RemoveByIndex 移除指定index位置
func (receiver *ArrayList[E]) RemoveByIndex(index int) E {
	if index < 0 || index >= receiver.Size() {
		panic("index out of range")
	}
	obj := receiver.elementData[index]
	// 判断是否是第一个
	if index == 0 {
		receiver.elementData = receiver.elementData[1:]
	} else if index == receiver.Size()-1 {
		receiver.elementData = receiver.elementData[:index]
	} else {
		receiver.elementData = append(receiver.elementData[:index], receiver.elementData[index+1:]...)
	}
	receiver.size = receiver.size - 1
	return obj
}

// AddFirst 添加指定第一个位置
func (receiver *ArrayList[E]) AddFirst(obj E) {
	receiver.AddByIndex(0, obj)
}

// AddLast 添加指定最后位置
func (receiver *ArrayList[E]) AddLast(obj E) {
	receiver.Add(obj)
}

// GetFirst 获取第一个位置
func (receiver *ArrayList[E]) GetFirst() E {
	return receiver.elementData[0]
}

// GetLast 获取最后位置
func (receiver *ArrayList[E]) GetLast() E {
	index := receiver.Size() - 1
	if index < 0 {
		panic("NoSuchElementException")
	}
	return receiver.elementData[index]
}

// Size 获取size
func (receiver *ArrayList[E]) Size() int {
	return receiver.size
}

// RemoveFirst 移除第一位
func (receiver *ArrayList[E]) RemoveFirst() E {
	return receiver.RemoveByIndex(0)
}

// RemoveLast 移除最后
func (receiver *ArrayList[E]) RemoveLast() E {
	return receiver.RemoveByIndex(receiver.Size() - 1)
}

// Clear 清空切片
func (receiver *ArrayList[E]) Clear() {
	receiver.elementData = receiver.emptyElementData[:0]
}

// Remove 删除
func (receiver *ArrayList[E]) Remove(obj E) bool {
	data := receiver.elementData
	size := receiver.size
	if &obj == nil {
		for i := 0; i < size; i++ {
			if reflect.DeepEqual(data[i], nil) {
				receiver.RemoveByIndex(i)
				break
			}
		}
	} else {
		for i := 0; i < size; i++ {
			if reflect.DeepEqual(data[i], obj) {
				receiver.RemoveByIndex(i)
			}
		}
	}
	return false
}

// RemoveIf 删除
func (receiver *ArrayList[E]) RemoveIf(predicate function.Predicate[E]) bool {
	ok := false
	for i, datum := range receiver.elementData {
		if predicate(datum) {
			receiver.RemoveByIndex(i)
			ok = true
		}
	}
	return ok
}

//// AddAll
////
////	Returns
////		bool
//func (receiver *AbstractCollection[E]) AddAll(c collection[E]) bool {
//	newSize := c.ToSlice()
//}

// -------------------- private func -----------------------

func (receiver *ArrayList[E]) add(e E, elementData []E, s int) {
	if s >= len(elementData) {
		elementData = receiver.grow()
	}
	receiver.elementData[s] = e
	receiver.size = s + 1
}

func (receiver *ArrayList[E]) newLength(oldLength, minGrowth, prefGrowth int) int {
	prefLength := oldLength + int(math.Max(float64(minGrowth), float64(prefGrowth))) // might overflow
	if 0 < prefLength && prefLength <= math.MaxInt32-8 {
		return prefLength
	} else {
		minLength := oldLength + minGrowth

		if minLength < 0 {
			panic("Required array length " + string(rune(oldLength)) + " + " + string(rune(minGrowth)) + " is too large")
		} else if minLength <= math.MaxInt32-8 {
			return math.MaxInt32 - 8
		} else {
			return minLength
		}
	}
}

func rangeCheckForAdd(index, size int) {
	if index > size || index < 0 {
		panic(outOfBoundsMsg(index, size))
	}
}

func outOfBoundsMsg(index, size int) string {
	return "Index: " + strconv.Itoa(index) + ", Size: " + strconv.Itoa(size)
}

func (receiver *ArrayList[E]) grow() []E {
	return receiver.grow2(receiver.Size() + 1)
}

func (receiver *ArrayList[E]) grow2(minCapacity int) []E {
	oldCapacity := len(receiver.elementData)
	if oldCapacity > 0 || &receiver.elementData != &receiver.emptyElementData {
		newCapacity := receiver.newLength(oldCapacity,
			minCapacity-oldCapacity,
			oldCapacity>>1)
		n := make([]E, newCapacity)
		copy(n, receiver.elementData)
		receiver.elementData = n
	} else {
		n := make([]E, int(math.Max(float64(defaultCapacity), float64(minCapacity))))
		receiver.elementData = n
	}
	return receiver.elementData
}
